#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>

#include "anytimer.h"

/*
 * 定义任务的结构体
 * */
struct job_st {
	int sec;
	job_t *job;
	char *arg;
	int flag;
};

static struct job_st *jobs[JOB_MAX];
static int inited = 0;
static struct sigaction alrm_action_save;

/*
 * 函数指针
 * 处理带有信息来源的事件处理
 * */
static void alrm_hander(int s, siginfo_t *info, void *unused)
{

	// 屏蔽除了内存发送出来的信号，避免其他程序信号干扰，可以使用kill -SIGALEM pid 进行测试
	if(info->si_code != SI_KERNEL)
	{
		printf("siginal is illegal！！！\n");
		return;
	}

	// 检查各个任务，是否到达执行时间
	for (int i = 0; i < JOB_MAX; i++) {
		if(jobs[i] != NULL)
		{
			jobs[i]->sec--;
			if(jobs[i]->sec < 0)
			{
				// 到达job的执行时间，调用job中的函数
			 	jobs[i]->job(jobs[i]->arg);	
				// 记录job的运行状态，标记已经运行结束
				jobs[i]->flag = 0;
			}
		}
	}
}

static void module_unload(void)
{
	// 恢复现场
	struct itimerval itv;

    sigaction(SIGALRM, &alrm_action_save, NULL);

    itv.it_interval.tv_sec = 0;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = 0;
    itv.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL, &itv, NULL);
	
	for (int i = 0; i < JOB_MAX; i++) {
		free(jobs[i]);
	}
}

static void module_load(void)
{

	struct sigaction siac;
	struct itimerval itv;
	
	siac.sa_sigaction = alrm_hander;
	sigemptyset(&siac.sa_mask);
	siac.sa_flags = SA_SIGINFO; // 表示信号触发的时候带有3个参数的指针函数
	sigaction(SIGALRM, &siac, &alrm_action_save);

	itv.it_interval.tv_sec = 1;
	itv.it_interval.tv_usec = 0;
	itv.it_value.tv_sec = 1;
	itv.it_value.tv_usec = 0;
	setitimer(ITIMER_REAL, &itv,NULL); // 信号 1s 定时发出

	// 钩子函数，卸载当前模块
	atexit(module_unload);
}

static int get_free_pos()
{
	for (int i = 0; i < JOB_MAX; i++) {
		if(jobs[i] == NULL)
		{
			return i;
		}
	}
	return -1;
}

int add_job(int sec, job_t *job, void *arg)
{
	struct job_st *me;
	int pos;
	if(!inited)
	{
		module_load();
		inited = 1;
	}

	if (sec < 0)
	{
		return -EINVAL;
	}

	pos = get_free_pos();
	if(pos < 0)
	{
		return -ENOSPC;
	}

	me = malloc(sizeof(*me));
	if(me == NULL)
	{
		return -ENOMEM;
	}

	me->sec = sec;
	me->job = job;
	me->arg = arg;
	me->flag = 1;

	jobs[pos] = me;
	printf("job[%d] is added!\n", pos);

	return pos;
}

/*
 * 取消任务
 * */
int at_cancel_job(int id)
{
	if(id < 0 || id > JOB_MAX || jobs[id] == NULL)
	{
		return -EINVAL;
	}
	printf("job[%d] is canceled!\n", id);
	jobs[id] = NULL;
	return 0;
}

/*
 * 任务统一回收
 * */
int at_wait_job(int id)
{
	if(jobs[id] != NULL && jobs[id]->flag == 0)
	{
		printf("job[%d] is waited!\n", id);
		jobs[id] = NULL;
	}
	return 0;
}

